package com.lin.cloud.disk.manage.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.lin.cloud.disk.common.enums.EDeleteStatus;
import com.lin.cloud.disk.common.enums.EUploadStatus;
import com.lin.cloud.disk.common.exception.BusinessException;
import com.lin.cloud.disk.entity.dto.DirectoryAndFileDTO;
import com.lin.cloud.disk.entity.pojo.Directory;
import com.lin.cloud.disk.entity.pojo.DirectoryClosure;
import com.lin.cloud.disk.entity.pojo.File;
import com.lin.cloud.disk.entity.request.directory.*;
import com.lin.cloud.disk.entity.request.file.GetUserFileRequest;
import com.lin.cloud.disk.entity.response.GetSpecifiedDayWithinFileAndDirectoryByDeleteResponse;
import com.lin.cloud.disk.entity.response.GetCurrentDirectoryAndFileListResponse;
import com.lin.cloud.disk.manage.IDirectoryManageService;
import com.lin.cloud.disk.service.IDirectoryClosureService;
import com.lin.cloud.disk.service.IDirectoryService;
import com.lin.cloud.disk.service.IFileService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 目录结构管理服务实现类
 *
 * @author ljc
 * @date 2020/12/30 22:45
 */
@Service
@Slf4j
public class DirectoryManageServiceImpl implements IDirectoryManageService {

    @Resource
    private IDirectoryService directoryService;

    @Resource(name = "directoryClosureServiceDocument")
    private IDirectoryClosureService directoryClosureService;

    @Resource
    private IFileService fileService;

    /**
     * 创建目录
     *
     * @param request
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createDirectory(CreateDirectoryRequest request) {
        // 是否存在父目录
        boolean existParentDirectory = false;
        boolean isRootDirectory = true;
        List<DirectoryClosure> ancestorList = null;
        // 1. 插入目录数据
        Directory directory = new Directory();
        directory.setUserId(request.getUserDTO().getId());
        directory.setDirectoryName(request.getDirectoryName());
        directory.setCreateBy(request.getUserDTO().getUsername());
        directory.setCompanyId(request.getUserDTO().getCompanyId());
        // 生成ID
        long directoryId = IdWorker.getId();
        directory.setId(directoryId);
        // 创建目录
        directoryService.createDirectory(directory);
        // 是否存在父目录
        if (null != request.getParentId() && StringUtils.isNotBlank(request.getParentId())) {
            isRootDirectory = false;
            // 查询是否存在该目录
            IsExistParentDirectoryRequest isExistParentDirectoryRequest = new IsExistParentDirectoryRequest();
            isExistParentDirectoryRequest.setUserId(request.getUserDTO().getId());
            isExistParentDirectoryRequest.setCompanyId(request.getUserDTO().getCompanyId());
            isExistParentDirectoryRequest.setParentId(request.getParentId());
            existParentDirectory = directoryService.isExistParentDirectory(isExistParentDirectoryRequest);
            // 存在父目录 则将请求的parentId设置为父目录 既构成子目录
            if (existParentDirectory) {
                // 2. 找到闭包表的祖先节点列表
                GetAncestorListRequest getAncestorListRequest = new GetAncestorListRequest();
                getAncestorListRequest.setUserId(request.getUserDTO().getId());
                getAncestorListRequest.setCompanyId(request.getUserDTO().getCompanyId());
                getAncestorListRequest.setDescendantList(Arrays.asList(request.getParentId()));
                getAncestorListRequest.setDistance(0);
                ancestorList = directoryClosureService.getAncestorList(getAncestorListRequest);
                // 如果祖先节点列表存在 则
                if (CollectionUtil.isNotEmpty(ancestorList)) {
                    ancestorList.forEach(ancestor -> {
                        // 孙子节点为当前节点
                        ancestor.setDescendant(String.valueOf(directoryId));
                        // 节点距离+1
                        ancestor.setDistance(ancestor.getDistance() + 1);
                        ancestor.setIsRoot(0);
                    });

                }
            }
        }
        // 最后闭包表插入一条自己的记录  祖先父子都是自己 距离为0
        DirectoryClosure directoryClosure = new DirectoryClosure();
        directoryClosure.setAncestor(String.valueOf(directoryId));
        directoryClosure.setDescendant(String.valueOf(directoryId));
        directoryClosure.setDistance(0);
        directoryClosure.setCompanyId(request.getUserDTO().getCompanyId().toString());
        directoryClosure.setIsRoot(isRootDirectory ? 1 : 0);
        directoryClosure.setUserId(request.getUserDTO().getId().toString());
        if (null == ancestorList) {
            ancestorList = new ArrayList<>(1);
        }
        ancestorList.add(directoryClosure);

        // 批量插入闭包表
        directoryClosureService.createDirectoryClosureList(ancestorList);

    }

    /**
     * 获取目录结构
     *
     * @param request
     * @return
     */
    @Override
    public List<Directory> getDirectoryPath(GetDirectoryPathRequest request) {

        // 不传参数 根目录
        if (StringUtils.isBlank(request.getDirectoryId())) {
            // 获取所有一级目录
//            GetRootDirectoryListRequest getRootDirectoryListRequest = new GetRootDirectoryListRequest();
//            getRootDirectoryListRequest.setUserId(request.getUserDTO().getId());
//            getRootDirectoryListRequest.setCompanyId(request.getUserDTO().getCompanyId());
//            List<DirectoryClosure> rootDirectoryList = directoryClosureService.getRootDirectoryList(getRootDirectoryListRequest);
//            if (CollectionUtil.isNotEmpty(rootDirectoryList)) {
//                List<Long> rootDirectoryIdList = rootDirectoryList.stream().map(DirectoryClosure::getAncestor).sorted().collect(Collectors.toList());
//                GetDirectoryListRequest getDirectoryListRequest = new GetDirectoryListRequest();
//                getDirectoryListRequest.setCompanyId(request.getUserDTO().getCompanyId());
//                getDirectoryListRequest.setUserId(request.getUserDTO().getId());
//                getDirectoryListRequest.setDirectoryPathList(rootDirectoryIdList);
//                List<Directory> directoryList = directoryService.getDirectoryByList(getDirectoryListRequest);
//                return directoryList;
//            }
            return Collections.EMPTY_LIST;
        } else {

            // 获取所有祖先节点包括自己
            GetAncestorListRequest getAncestorListRequest = new GetAncestorListRequest();
            getAncestorListRequest.setUserId(request.getUserDTO().getId());
            getAncestorListRequest.setCompanyId(request.getUserDTO().getCompanyId());
            getAncestorListRequest.setDescendantList(Arrays.asList(request.getDirectoryId()));
            getAncestorListRequest.setDistance(0);
            List<DirectoryClosure> ancestorList = directoryClosureService.getAncestorList(getAncestorListRequest);
            if (CollectionUtil.isNotEmpty(ancestorList)) {
                // 路径列表
                List<String> directoryPathList = ancestorList.stream().sorted(Comparator.comparing(DirectoryClosure::getDistance).reversed()).map(DirectoryClosure::getAncestor).collect(Collectors.toList());
                // 查询路径详情
                GetDirectoryListRequest getDirectoryListRequest = new GetDirectoryListRequest();
                getDirectoryListRequest.setCompanyId(request.getUserDTO().getCompanyId());
                getDirectoryListRequest.setUserId(request.getUserDTO().getId());
                getDirectoryListRequest.setDirectoryPathList(directoryPathList);
                List<Directory> directoryList = directoryService.getDirectoryByList(getDirectoryListRequest);
                // 按照 distance大小排序
                Collections.sort(directoryList, new Comparator<Directory>(){

                    @Override
                    public int compare(Directory o1, Directory o2) {
                        int index1 = directoryPathList.indexOf(o1.getId());
                        int index2 = directoryPathList.indexOf(o2.getId());
                        return index1 - index2;
                    }
                });
                return directoryList;
            }
        }
        return Collections.EMPTY_LIST;
    }

    /**
     * 修改目录名字
     *
     * @param request
     */
    @Override
    public void updateDirectoryName(UpdateDirectoryNameRequest request) {
        if (StringUtils.isNotBlank(request.getDirectoryName())) {
            Directory directory = new Directory();
            directory.setUpdateBy(request.getUserDTO().getUsername());
            directory.setUpdateTime(new Date());
            directory.setDirectoryName(request.getDirectoryName());
            directory.setId(request.getId());
            directoryService.updateDirectoryName(directory);
        }
    }


    /**
     * 逻辑删除目录
     *
     * @param request
     */
    @Override
    public void logicRemoveDirectory(RemoveDirectoryRequest request) {
        if (CollectionUtil.isNotEmpty(request.getIdList())) {
            directoryService.logicRemoveDirectory(request);
        }
    }

    /**
     * 物理删除目录
     *
     * @param request
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void physicistRemoveDirectory(RemoveDirectoryRequest request) {
        int removeCount = 0;
        if (CollectionUtil.isNotEmpty(request.getIdList())) {
            removeCount = directoryService.physicistRemoveDirectory(request);
        }
        // 删除的数量不是0 则需要删除闭包表的数据
        if (0 != removeCount) {
            // 删除祖先与子孙子节点都是 request.getIdList()的数据
            directoryClosureService.physicistRemoveDirectoryClosure(request);
        }
    }

    /**
     * 逻辑恢复目录
     *
     * @param request
     */
    @Override
    public void logicRestoreDirectory(RestoreDirectoryRequest request) {
        if (CollectionUtil.isNotEmpty(request.getIdList())) {
            directoryService.logicRestoreDirectory(request);
        }
    }

    /**
     * 移动目录
     *
     * @param request
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void moveDirectory(MoveDirectoryRequest request) {
        // 获取IDList(B C D等)所有子孙节点闭包数据 包括自己
        if (CollectionUtil.isEmpty(request.getMoveDirectoryIdList())) {
            throw new BusinessException("移动的目录ID不能为空");
        }
        boolean moveToRootDirectory = false;
        String moveInDirectoryId = request.getMoveInDirectoryId();
        if (StringUtils.isBlank(moveInDirectoryId) || "-1".equals(moveInDirectoryId)){
            moveToRootDirectory = true;
        }
        List<DirectoryClosure> ancestorList = Collections.EMPTY_LIST;
        List<DirectoryClosure> addDirectoryClosureList = new ArrayList<>();
        List<DirectoryClosure> updateDirectoryClosureList = new ArrayList<>();
        List<Long> removeIdList = new ArrayList<>();
        // 查询 moveInDirectoryId 所有祖先节点 包括自己
        if (!moveToRootDirectory) {
            GetAncestorListRequest getAncestorListRequest = new GetAncestorListRequest();
            getAncestorListRequest.setUserId(request.getUserDTO().getId());
            getAncestorListRequest.setCompanyId(request.getUserDTO().getCompanyId());
            getAncestorListRequest.setDescendantList(Arrays.asList(moveInDirectoryId));
            getAncestorListRequest.setDistance(0);
            ancestorList = directoryClosureService.getAncestorList(getAncestorListRequest);
            if (CollectionUtil.isEmpty(ancestorList)) {
                throw new BusinessException("目标目录不存在");
            }
        }
        // 子孙闭表列表数据 包括自己
        GetDescendantListAndMeByIdListRequest getDescendantListAndMeByIdListRequest = new GetDescendantListAndMeByIdListRequest();
        getDescendantListAndMeByIdListRequest.setUserId(request.getUserDTO().getId());
        getDescendantListAndMeByIdListRequest.setCompanyId(request.getUserDTO().getCompanyId());
        getDescendantListAndMeByIdListRequest.setDescendantList(request.getMoveDirectoryIdList());
        List<DirectoryClosure> descendantListAndMeList = directoryClosureService.getDescendantListAndMeByIdList(getDescendantListAndMeByIdListRequest);
        // 如果是移动到根目录
        if (moveToRootDirectory) {
            descendantListAndMeList.forEach(directoryClosure ->{
                if (0 == directoryClosure.getDistance()){
                    // 设置为根目录
                    directoryClosure.setIsRoot(1);
                    updateDirectoryClosureList.add(directoryClosure);
                }
            });
        } else {
            // 不是根目录
            DirectoryClosure directoryClosure = null;
            int parentMaxPath = 1;
            // 计算父节点最大深度
            parentMaxPath = parentMaxPath + ancestorList.stream().mapToInt(DirectoryClosure::getDistance).max().getAsInt();
            // 将descendantListAndMeList 移动到新的目录之下
            // 顺序是从后往前  需要反转一下
             Collections.reverse(ancestorList);
            int parentPath = 0;
                for (DirectoryClosure parentDirectoryClosure : ancestorList) {
                    for (DirectoryClosure sumDirectoryClosure : descendantListAndMeList) {
                        directoryClosure = new DirectoryClosure();
                        directoryClosure.setUserId(request.getUserDTO().getId().toString());
                        directoryClosure.setCompanyId(request.getUserDTO().getCompanyId().toString());
                        directoryClosure.setAncestor(parentDirectoryClosure.getAncestor());
                        directoryClosure.setDescendant(sumDirectoryClosure.getDescendant());
                        directoryClosure.setIsRoot(0);
                        directoryClosure.setDistance(sumDirectoryClosure.getDistance() + parentMaxPath - parentPath);
                        addDirectoryClosureList.add(directoryClosure);
                    }
                    parentPath++;
            }
        }
        // 获取移动节点的所有祖先
        GetAncestorListRequest getAncestorListRequest = new GetAncestorListRequest();
        getAncestorListRequest.setUserId(request.getUserDTO().getId());
        getAncestorListRequest.setCompanyId(request.getUserDTO().getCompanyId());
        getAncestorListRequest.setDescendantList(request.getMoveDirectoryIdList());
        getAncestorListRequest.setDistance(1);
        ancestorList = directoryClosureService.getAncestorList(getAncestorListRequest);
        // 如果获取不到父节点 则代表当前是根节点
        if (CollectionUtil.isEmpty(ancestorList) && !moveToRootDirectory){
            // 更新移动的节点
            descendantListAndMeList.forEach(directoryClosure ->{
                if (0 == directoryClosure.getDistance()){
                    // 设置为非根目录
                    directoryClosure.setIsRoot(0);
                    updateDirectoryClosureList.add(directoryClosure);
                }
            });
        }
        List<String> ancestorIdList = ancestorList.stream().map(DirectoryClosure::getAncestor).collect(Collectors.toList());
        // 获取移动节点的所有子孙节点 包括自己
        List<String> descendantIdList = descendantListAndMeList.stream().map(DirectoryClosure::getDescendant).collect(Collectors.toList());
        MoveRemoveDirectoryRequest moveRemoveDirectoryRequest = new MoveRemoveDirectoryRequest();
        moveRemoveDirectoryRequest.setUserId(request.getUserDTO().getId());
        moveRemoveDirectoryRequest.setAncestorIdList(ancestorIdList);
        moveRemoveDirectoryRequest.setDescendantIdList(descendantIdList);
        moveRemoveDirectoryRequest.setCompanyId(request.getUserDTO().getCompanyId());
        // 删除移动前的连线
        directoryClosureService.physicistMoveRemoveDirectoryClosure(moveRemoveDirectoryRequest);
        if(CollectionUtil.isNotEmpty(updateDirectoryClosureList)) {
            // 修改
            directoryClosureService.batchUpdateDirectoryClosure(updateDirectoryClosureList);
        }
        if(CollectionUtil.isNotEmpty(addDirectoryClosureList)) {
            // 添加到新的路径之下
            directoryClosureService.createDirectoryClosureList(addDirectoryClosureList);
        }


    }


    /**
     * 获取当前目录下的文件与目录
     * @param request
     * @return
     */
    @Override
    public GetCurrentDirectoryAndFileListResponse getCurrentDirectoryAndFileList(GetCurrentDirectoryAndFileListRequest request){
        // 获取当前目录路径
        GetDirectoryPathRequest getDirectoryPathRequest = new GetDirectoryPathRequest();
        getDirectoryPathRequest.setDirectoryId(request.getDirectoryId());
        getDirectoryPathRequest.setUserDTO(request.getUserDTO());
        List<Directory> currentDirectoryPathList = this.getDirectoryPath(getDirectoryPathRequest);
        // 获取当前目录之下一层的文件夹
        GetNextLevelDirectoryListRequest getNextLevelDirectoryListRequest = new GetNextLevelDirectoryListRequest();
        getNextLevelDirectoryListRequest.setDirectoryId(request.getDirectoryId());
        getNextLevelDirectoryListRequest.setUserId(request.getUserDTO().getId());
        getNextLevelDirectoryListRequest.setCompanyId(request.getUserDTO().getCompanyId());
        List<DirectoryClosure> currentDirectoryList = directoryClosureService.getNextLevelDirectoryList(getNextLevelDirectoryListRequest);
        List<Directory> directoryByList = Collections.EMPTY_LIST;
        if (CollectionUtil.isNotEmpty(currentDirectoryList)){
            GetDirectoryListRequest getDirectoryListRequest = new GetDirectoryListRequest();
            List<String> directoryIdList = currentDirectoryList.stream().map(DirectoryClosure::getDescendant).collect(Collectors.toList());
            getDirectoryListRequest.setUserId(request.getUserDTO().getId());
            getDirectoryListRequest.setCompanyId(request.getUserDTO().getCompanyId());
            getDirectoryListRequest.setDirectoryPathList(directoryIdList);
            directoryByList = directoryService.getDirectoryByList(getDirectoryListRequest);
        }
        // 获取当前目录下的一层文件
        GetUserFileRequest getUserFileRequest = new GetUserFileRequest();
        getUserFileRequest.setUserId(request.getUserDTO().getId());
        if (null == request.getDirectoryId()){
            getUserFileRequest.setDirectoryId("-1");
        }else{
            getUserFileRequest.setDirectoryId(request.getDirectoryId());
        }
        getUserFileRequest.setIsDelete(EDeleteStatus.UN_DELETE.getStatus());
        getUserFileRequest.setUploadStatus(EUploadStatus.DONE_UPLOAD.getStatus());
        List<File> currenFileList = fileService.getFileList(getUserFileRequest);
        List<DirectoryAndFileDTO> directoryAndFileDTOList = setDirectoryAndFileParameter(directoryByList, currenFileList, Comparator.comparing(DirectoryAndFileDTO::getCreateTime));
        GetCurrentDirectoryAndFileListResponse response = new GetCurrentDirectoryAndFileListResponse();
        response.setCurrentDirectoryPathList(currentDirectoryPathList);
        response.setDirectoryAndFileDTOList(directoryAndFileDTOList);

        return response;
    }

    /**
     * 获取指定时间内删除的文件与目录
     * @param request
     * @return
     */
    @Override
    public GetSpecifiedDayWithinFileAndDirectoryByDeleteResponse getSpecifiedDayWithinFileAndDirectoryByDelete(GetSpecifiedDayWithinFileAndDirectoryByDeleteRequest request){
        // 获取已删除的目录
        // 获取已删除的文件
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy/MM/dd");
        GetUserFileRequest getUserFileRequest = new GetUserFileRequest();
        GetDirectoryListRequest getDirectoryListRequest = new GetDirectoryListRequest();

        getDirectoryListRequest.setCompanyId(request.getUserDTO().getCompanyId());
        getDirectoryListRequest.setUserId(request.getUserDTO().getId());
        getDirectoryListRequest.setIsDelete(true);

        Integer specifiedDayWithin = request.getSpecifiedDayWithin();
        if (null == specifiedDayWithin || specifiedDayWithin < 1){
            specifiedDayWithin = 1;
        }

        Calendar calendar = Calendar.getInstance();
        // 当前时间为结束时间
        calendar.add(Calendar.DATE, -specifiedDayWithin);
        // dayAgo天前为开始时间

        getDirectoryListRequest.setStartTime(simpleDateFormat.format(calendar.getTime()));
        getUserFileRequest.setStartTime(simpleDateFormat.format(calendar.getTime()));
        getUserFileRequest.setHasCreateTime(false);

        List<Directory> directoryList = directoryService.getDirectoryByList(getDirectoryListRequest);

        getUserFileRequest.setUserId(request.getUserDTO().getId());
        getUserFileRequest.setUploadStatus(EUploadStatus.DONE_UPLOAD.getStatus());
        getUserFileRequest.setIsDelete(EDeleteStatus.DELETE.getStatus());
        List<File> fileList = fileService.getFileList(getUserFileRequest);

        List<DirectoryAndFileDTO> directoryAndFileDTOList = setDirectoryAndFileParameter(directoryList, fileList, Comparator.comparing(DirectoryAndFileDTO::getUpdateTime));

        GetSpecifiedDayWithinFileAndDirectoryByDeleteResponse response = new GetSpecifiedDayWithinFileAndDirectoryByDeleteResponse();
        if (CollectionUtil.isEmpty(directoryAndFileDTOList)){
            response.setDirectoryAndFileDTOList(Collections.EMPTY_LIST);
        }else {
            response.setDirectoryAndFileDTOList(directoryAndFileDTOList);
        }

        return response;
    }


    /**
     * 懒加载获取目录树
     * @param request
     * @return
     */
    @Override
    public List<Directory> getLazyDirectoryTree(GetLazyDirectoryTreeRequest request){

        // 获取当前目录之下一层的文件夹
        GetNextLevelDirectoryListRequest getNextLevelDirectoryListRequest = new GetNextLevelDirectoryListRequest();
        getNextLevelDirectoryListRequest.setDirectoryId(request.getDirectoryId());
        getNextLevelDirectoryListRequest.setUserId(request.getUserDTO().getId());
        getNextLevelDirectoryListRequest.setCompanyId(request.getUserDTO().getCompanyId());
        List<DirectoryClosure> currentDirectoryList = directoryClosureService.getNextLevelDirectoryList(getNextLevelDirectoryListRequest);

        List<Directory> directoryByList = Collections.EMPTY_LIST;
        if (CollectionUtil.isNotEmpty(currentDirectoryList)){
            GetDirectoryListRequest getDirectoryListRequest = new GetDirectoryListRequest();
            List<String> directoryIdList = currentDirectoryList.stream().map(DirectoryClosure::getDescendant).collect(Collectors.toList());
            getDirectoryListRequest.setUserId(request.getUserDTO().getId());
            getDirectoryListRequest.setCompanyId(request.getUserDTO().getCompanyId());
            getDirectoryListRequest.setDirectoryPathList(directoryIdList);
            directoryByList = directoryService.getDirectoryByList(getDirectoryListRequest);
        }
        return directoryByList;
    }

    /**
     * 分装目录与文件参数
     * @param directoryByList
     * @param fileList
     * @param comparing
     * @return
     */
    private List<DirectoryAndFileDTO> setDirectoryAndFileParameter(List<Directory> directoryByList, List<File> fileList, Comparator<DirectoryAndFileDTO> comparing) {
        List<DirectoryAndFileDTO> directoryAndFileDTOList = new ArrayList<>();

        // 目录数据
        if (CollectionUtil.isNotEmpty(directoryByList)) {
            directoryByList.forEach(directory -> {
                DirectoryAndFileDTO directoryAndFileDTO = new DirectoryAndFileDTO();
                BeanUtil.copyProperties(directory, directoryAndFileDTO);
                directoryAndFileDTO.setIsDir(true);
                directoryAndFileDTOList.add(directoryAndFileDTO);
            });
        }

        // 文件数据
        if (CollectionUtil.isNotEmpty(fileList)) {
            fileList.forEach(file -> {
                DirectoryAndFileDTO directoryAndFileDTO = new DirectoryAndFileDTO();
                BeanUtil.copyProperties(file, directoryAndFileDTO);
                directoryAndFileDTO.setIsDir(false);
                directoryAndFileDTOList.add(directoryAndFileDTO);
            });
        }

        // 整体通过createTime排序
        directoryAndFileDTOList.sort(Comparator.comparing(DirectoryAndFileDTO::getCreateTime).reversed());
        return directoryAndFileDTOList;
    }



}
